/**
 * 
 */
package com.redsoft.spirit.service;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.redsoft.spirit.dao.MenuRepository;
import com.redsoft.spirit.dao.MenuRoleRepository;
import com.redsoft.spirit.entity.Menu;
import com.redsoft.spirit.entity.MenuRole;
import com.redsoft.spirit.entity.TreeNode;
import com.redsoft.spirit.util.BeanUtils;

/**
 * 菜单的业务逻辑层.
 * 
 * <pre>
 * 	提供菜单部分功能的业务操作
 * </pre>
 * 
 * @author 杨雷
 * @since 1.0
 */
@Service
@Transactional
public class MenuService {

	@Autowired
	private MenuRepository menuRepository;

	@Autowired
	private MenuRoleRepository menuRoleRepository;
	
	@Value("${jdbc.db-type}")
	private String dbType;

	/**
	 * 
	 * 菜单树的建立.
	 * <pre>
	 * 	菜单树的建立
	 * </pre>
	 * 
	 * @author 杨雷
	 * @param userId 
	 * @return
	 */
	public List<TreeNode> getJsonTree(String userId) {
		List<TreeNode> trees = new ArrayList<>();

		//先查询出所有的码表项，然后遍历，创建出对应的treeNode项
		//如果是 超级管理员则查询全部，如果不是则查询这个人所拥有的所有菜单
		List<Menu> menus = new ArrayList<>();

		if("10000".equals(userId)) {
//			String sql = "SELECT * FROM sys_menu WHERE FIND_IN_SET(id,getSonMenu(0))";
			
			String sql = "SELECT * FROM sys_menu order by display asc";
			menus = menuRepository.sqlQuery(sql);
		} else {
			menus = menuRepository.getMenusByUser(userId);
		}

		trees = initTree(menus);
		return trees;
	}

	private List<TreeNode> initTree(List<Menu> menus) {

		List<TreeNode> trees = new ArrayList<>();
		Map<String, TreeNode> map = new LinkedHashMap<>();

		for (Menu menu : menus) {
			TreeNode node = new TreeNode();
			node.setId(menu.getId());
			node.setLabel(menu.getMenuName());
			node.setIconCls(menu.getMenuIco());
			node.setOtherValue(menu.getUrl());
			node.setChildren(new ArrayList<TreeNode>());
			node.setParentId(menu.getParentId());

			map.put(node.getId(), node);	
		}

		//当codeTable的parentId从 map中可以获取到时候，把这个codeTable对应的map中的node取出来，放到parentId的node的children中
		for (Menu menu : menus) {
			if(map.containsKey(menu.getParentId())) {
				map.get(menu.getParentId()).getChildren().add(map.get(menu.getId()));
				//	map.remove(codeTable.getId());
			}
		}

		for (TreeNode treeNode : map.values()) {
			if ("0".equals(treeNode.getParentId())) {
				trees.add(treeNode);
			}
		}
		return trees;
	}

	/**
	 * 
	 * 递归查询菜单树.
	 * <pre>
	 * 	递归查询菜单树
	 * </pre>
	 * 
	 * @author 杨雷
	 * @param menu
	 * @param userId 
	 * @return
	 */
	private TreeNode tree(Menu menu, String userId) {
		TreeNode node = new TreeNode();
		node.setId(menu.getId());
		node.setLabel(menu.getMenuName());
		node.setIconCls(menu.getMenuIco());
		node.setOtherValue(menu.getUrl());

		List<Menu> menus = new ArrayList<>();

		//如果是 超级管理员则查询全部，如果不是则查询这个人所拥有的所有菜单
		if("1".equals(userId)) {
			menus = menuRepository.findByParentId(menu.getId());
		} else {
			menus = menuRepository.getMenusByUser(userId, menu.getId());
		}

		List<TreeNode> children = new ArrayList<>();

		for (Menu menuChild : menus) {
			TreeNode nodeChild = tree(menuChild, userId);
			children.add(nodeChild);
		}
		node.setChildren(children);
		return node;
	}

	/**
	 * 
	 * 根据id获取menu实体类.
	 * <pre>
	 * 	根据id获取menu实体类
	 * </pre>
	 * 
	 * @author 杨雷
	 * @param id
	 * @return
	 */
	public Menu get(String id) {
		return menuRepository.findById(id);
	}

	/**
	 * 
	 * 根据id获取menu的儿子级菜单.
	 * <pre>
	 * 	根据id获取menu的儿子级菜单
	 * </pre>
	 * 
	 * @author 杨雷
	 * @param id
	 * @return
	 */
	public List<Menu> getChildrenMenu(String id) {
		return  menuRepository.findByParentId(id);
	}

	/**
	 * 
	 * 更新菜单.
	 * <pre>
	 * 	先从数据库查询出menu,然后赋值新的值到老实体类上
	 * </pre>
	 * 
	 * @author 杨雷
	 * @param menu
	 * @throws Exception 
	 */
	public void updateMenu(Menu menu) throws Exception {
		Menu oldMenu = menuRepository.findById(menu.getId());
		BeanUtils.copyBeanNotNull2Bean(menu, oldMenu);
		menuRepository.save(menu);	
	}

	/**
	 * 保存新的菜单
	 * 
	 * <pre>
	 * 保存新的菜单
	 * </pre>
	 * 
	 * @author 杨雷
	 * @param menu
	 * @throws Exception 
	 */
	public void addMenu(Menu menu) throws Exception {
		if("".equals(menu.getId())) {
			menu.setIsActive(1);
			menuRepository.save(menu);		
		} else {
			Menu oldMenu = menuRepository.findById(menu.getId());
			BeanUtils.copyBeanNotNull2Bean(menu, oldMenu);
			menuRepository.save(oldMenu);
		}
	}

	/**
	 * 为某个菜单分配角色
	 * 
	 * <pre>
	 * 为某个菜单分配角色
	 * </pre>
	 * 
	 * @author 杨雷
	 * @param menuId 
	 * @param list
	 */
	public void addMenuRole(String menuId, List<String> list) {

		//先删除这个菜单下和角色的所有关系
		menuRoleRepository.deleteByMenuId(menuId);

		for (String roleId : list) {
			MenuRole mr = new MenuRole();
			mr.setMenuId(menuId);
			mr.setRoleId(roleId);

			menuRoleRepository.save(mr);
		}	
	}

	/**
	 * 删除菜单
	 * 
	 * <pre>
	 * 	删除菜单的同时需要删除菜单和角色的关系,并删除所有子孙节点的菜单以及本条
	 * </pre>
	 * 
	 * @author 杨雷
	 * @param id
	 * @return
	 */
	public void deleteMenu(String id) {
		String sql = "";
		
		//如果是mysql的话，则使用存储过程完成这段返回树形结构的数据
		if("mysql".equals(dbType.toLowerCase())) {
			sql = "SELECT * FROM sys_menu WHERE FIND_IN_SET(id,getSonMenu(?))";

		} else if ("oracle".equals(dbType.toLowerCase())) {
			sql = "select * from sys_menu start with id = ? connect by prior id = PARENT_ID";
		} else if("sqlserver".equals(dbType.toLowerCase())){
			sql = "with menu_temp as ( select *,0 AS LevelID from sys_menu WHERE id=  ? UNION ALL SELECT a.*,(LevelID + 1) AS LevelID"
					+ " from sys_menu a INNER JOIN menu_temp b ON a.PARENT_ID = b.id) SELECT * FROM menu_temp";
		}

		//查询本菜单以及子孙节点菜单
		List<Menu> menus = menuRepository.sqlQuery(sql, id);
		for (Menu menu : menus) {
			menuRepository.delete(menu);
			menuRoleRepository.deleteByMenuId(menu.getId());
		}
	}

	/**
	 * 根据菜单查询拥有该菜单的角色
	 * 
	 * <pre>
	 * 返回角色的id数组
	 * </pre>
	 * 
	 * @author 杨雷
	 * @param menuId
	 * @return
	 */
	public List<String> getRoleByMenu(String menuId) {
		return menuRoleRepository.getRoleByMenu(menuId);
	}

	/**
	 * 根据用户查询这个人所拥有的所有菜单
	 * 
	 * <pre>
	 * 	先查询这个用户所有的角色，然后查询所有角色的所有菜单，去重复,用sql实现
	 * </pre>
	 * 
	 * @author 杨雷
	 * @param userId
	 * @return
	 */
	public List<TreeNode> getJsonTreeByUser(String userId) {
		List<TreeNode> trees = new ArrayList<>();

		//先查询出所有的码表项，然后遍历，创建出对应的treeNode项
		//如果是 超级管理员则查询全部，如果不是则查询这个人所拥有的所有菜单
		List<Menu> menus = new ArrayList<>();
		menus = menuRepository.getMenusByUser(userId);
		trees = initTree(menus);

		//		//先查询父ID为0的菜单
		//		List <Menu> menus = menuRepository.getMenusByUser(userId, "0");
		//		
		//		for (Menu menu : menus) {
		//			TreeNode node = tree(menu, userId);
		//				
		//			trees.add(node);
		//		}

		return trees;
	}

	/**
	 * 获取所有的菜单
	 * 
	 * <pre>
	 * 获取所有的菜单
	 * </pre>
	 * 
	 * @author 李晓东
	 * @param userId
	 * @return
	 */
	public List<TreeNode> getAllJsonTreeByUser(String userId) {
		List<TreeNode> trees = new ArrayList<>();

		//先查询出所有的码表项，然后遍历，创建出对应的treeNode项
		//如果是 超级管理员则查询全部，如果不是则查询这个人所拥有的所有菜单
		List<Menu> menus = new ArrayList<>();
		if("10000".equals(userId)) {
			String sql = "SELECT * FROM sys_menu";
			menus = menuRepository.sqlQuery(sql);
		} else {
			menus = menuRepository.getMenusByUser(userId);
		}
		trees = initTree(menus);
		return trees;
	}

	/**
	 * 根据当前角色查询当前角色的所有菜单
	 * 
	 * <pre>
	 * 根据当前角色查询当前角色的所有菜单的id数组
	 * </pre>
	 * 
	 * @author 杨雷
	 * @param roleId
	 * @return
	 */
	public List<Menu> getMenuIdsByRole(String roleId) {
		String sql = "SELECT m.id "
				+ " FROM sys_menu m "
				+ " WHERE m.id IN("
				+ " SELECT mr.menu_id "
				+ " FROM sys_menu_role mr "
				+ " WHERE mr.role_id = ? and mr.indeterminate_flag ='0'"
				+ ") order by m.display asc ";
		
		return menuRepository.sqlQuery(sql, new Object[]{roleId});
//		return menuRepository.getMenuIdsByRole(roleId);
	}
}
